package com.hotel.controller;

import com.hotel.entity.Orders;
import com.hotel.entity.RoomType;
import com.hotel.entity.User;
import com.hotel.response.MessageUtils;
import com.hotel.response.RestResponse;
import com.hotel.service.OrdersService;
import com.hotel.service.RoomTypeService;
import com.hotel.service.UserService;
import com.hotel.utils.CommonRedisHelperUtil;
import com.hotel.utils.RedisKeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

import static com.hotel.utils.OrderIdByTimeUtil.getOrderIdByTime;

/**
 * @author 夏智力
 * @FileName BookingController
 * @date 2021/6/24 14:52
 * @Software: IntelliJ IDEA
 */
@RestController
@RequestMapping("/booking")
public class BookingController {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RoomTypeService roomTypeService;

    @Autowired
    private UserService userService;

    @Autowired
    private OrdersService ordersService;

    @Autowired
    private CommonRedisHelperUtil commonRedisHelperUtil;

    // 显示余量
    //
    //
    //    @RequiresPermissions("user:add")
    @RequestMapping(path = "/allowance/list", method = RequestMethod.GET)
    @CrossOrigin
    public RestResponse allowance(String startTime,String endTime) {
        // 根据日期生成redisKey

        String[] split0 = startTime.split("-");
        String[] split1 = endTime.split("-");
        int sum = Integer.valueOf(split1[2]) - Integer.valueOf(split0[2]);
        String[] redisKey = new String[sum];
        List<RoomType> list = new ArrayList<>();

        for (int i = 0; i < sum; i++) {
            redisKey[i] = RedisKeyUtil.getAllowanceKey(split0[0], split0[1], String.valueOf(Integer.valueOf(split0[2]) + i));
            List<RoomType> roomTypes = new ArrayList<>();
            if (redisTemplate.hasKey(redisKey[i])) {
                roomTypes = redisTemplate.opsForHash().values(redisKey[i]);
            } else {
                roomTypes = roomTypeService.selectRoomType();
                for (RoomType roomType : roomTypes) {
                    redisTemplate.opsForHash().put(redisKey[i], String.valueOf(roomType.getId()), roomType);
                }
            }
            if (list.size() == 0){
                list = roomTypes;
            }else{
                Iterator<RoomType> iterator = roomTypes.iterator();
                for (int j = 0; j < list.size(); j++) {     // list
                    RoomType list1 =list.get(j);
                    while(iterator.hasNext()) {            // temp
                        RoomType temp = iterator.next();
                        if( list1.getId() == temp.getId() ) {
                            list1.setNumbers( list1.getNumbers() > temp.getNumbers() ? temp.getNumbers() : list1.getNumbers() );
                            list.remove(j);
                            list.add(list1);
                            break;
                        }
                    }
                }
            }
        }
        return MessageUtils.success(list);
    }

    // 预订房间
    @RequestMapping(path = "/booking/do", method = RequestMethod.POST)
    public RestResponse goRoomType(int userId, String startTime, String endTime, int typeId) {
        // 根据日期生成redisKey
        String[] split0 = startTime.split("-");
        String[] split1 = endTime.split("-");
        RoomType roomType = null;
        boolean temp = true;
        int sum = Integer.valueOf(split1[2]) - Integer.valueOf(split0[2]);
        boolean lock[] = new boolean[sum];
        String[] redisKey = new String[sum];
        String[] lockKey = new String[sum];

        for (int i = 0; i < sum; i++) {
            redisKey[i] = RedisKeyUtil.getAllowanceKey(split0[0], split0[1], String.valueOf(Integer.valueOf(split0[2])+i));
            lockKey[i] = redisKey[i] + ":" + typeId;  // 分布式锁
            lock[i] = commonRedisHelperUtil.lock(lockKey[i]); // 原子化获取锁
            if (!lock[i]) {
                // 设置失败次数计数器, 当到达5次时, 返回失败
                int failCount = 1;
                while (failCount <= 5) {
                    // 等待100ms重试
                    try {
                        Thread.sleep(100l);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (!commonRedisHelperUtil.lock(lockKey[i])) {
                        failCount++;
                    } else {
                        lock[i] = commonRedisHelperUtil.lock(lockKey[i]);
                    }
                }
                temp = temp && lock[i];
            }
        }

        if (!temp) {
            for (int i = 0; i < sum; i++) {
                if (lock[i]) {
                    commonRedisHelperUtil.delete(lockKey[i]);//释放锁
                }
            }
            return MessageUtils.success("请重试");
        } else {
            for (int i = 0; i < sum; i++) {
                roomType = (RoomType) redisTemplate.opsForHash().get(redisKey[i], String.valueOf(typeId));
                if (roomType.getNumbers() > 0) {
                    roomType.setNumbers(roomType.getNumbers() - 1);
                    redisTemplate.opsForHash().put(redisKey[i], String.valueOf(typeId), roomType);
                }
                commonRedisHelperUtil.delete(lockKey[i]);
            }
            Orders orders = orderGeneration(userId, roomType, startTime, endTime, sum);
            return MessageUtils.success("预订成功",orders);
        }

    }

    @RequestMapping(path = "/update/pay", method = RequestMethod.POST)
    public RestResponse updatePayStatus(String orderNo) {
        ordersService.updatePayStatusByOrder(orderNo, 1);
        return MessageUtils.success("支付成功");
    }

    // 订单生成
    private Orders orderGeneration(int userId, RoomType roomType, String startTime, String endTime, int sum) {
        User user = userService.selectById(userId);
        Orders order = new Orders();
        Date date = new Date();
        order.setOrderNo(getOrderIdByTime(userId));
        order.setUserId(user.getId());
        order.setUsername(user.getUsername());
        order.setName(user.getName());
        order.setIdCard(user.getIdCard());
        order.setPhone(user.getPhone());
        order.setTypeName(roomType.getTypeName());
        order.setStartTime(startTime);
        order.setEndTime(endTime);
        order.setPayStatus(0);
        order.setAmount(roomType.getAmount() * sum);
        order.setPlaceTime(date);
        ordersService.addOrder(order);
        return order;
    }
}
